/***************************************************************
 *  Copyright (c) 2007 by GroupMe! Team (www.groupme.net)
 *  All rights reserved.
 *
 *  This file is part of the GroupMe! Project. Source code of 
 *  this project is closed and redistribution of this code is
 *  prohibited. 
 *  
 *  Contact: http://www.groupme.net
 *
 *  This copyright notice MUST APPEAR in all copies of the file!
 ***************************************************************/
package net.groupme.search.game;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import net.groupme.controller.model.SearchResult;
import net.groupme.exceptions.search.SearchEngineException;
import net.groupme.search.flickr.FlickrSearchEngine;
import net.groupme.search.google.GoogleSearchEngine;

/**
 * created on 11.02.2008
 * 
 * This class/interface...
 * 
 * @author Patrick Siehndel <a
 *         href="mailto:patrick.siehndel@gmx.de">patrick.siehndel@gmx.de</a>
 * @author last edited by: $Author: patrick $
 * 
 * @version $Revision: 1.2 $ $Date: 2008-02-28 14:49:55 $
 */
public class GameSearchEngine {

	/** Logger for this class and subclasses */
	protected final Log logger = LogFactory.getLog(getClass());

	/**
	 * Returns an Array 30 of {@link SearchResult} instances that suit the given
	 * keywords the first 10 results are from the google search, result 11-20
	 * are from flicker and the last 10 are from youtube.com
	 * 
	 * @param queryKeyword
	 *            The Keyword which is searched for
	 * @return
	 */
	public List<SearchResult> searchForGame(String queryKeyword) {
		logger.info("Searching for " + queryKeyword
				+ " with the GameSearchEngine");
		List<SearchResult> resultList = new ArrayList<SearchResult>();
		List<SearchResult> googleList = (new GoogleSearchEngine().searchGoogle(
				queryKeyword, null, 10));
		List<SearchResult> flickrList = new ArrayList<SearchResult>();

		try {
			flickrList = (new FlickrSearchEngine().searchForFlickrPhotos(
					queryKeyword, 9));
		} catch (SearchEngineException e) {
			logger
					.error(
							"Error while searching using the GameSearch GroupMe! search engine.",
							e);
			e.printStackTrace();
		}
		List<SearchResult> youtubeList = new GoogleSearchEngine().searchGoogle(
				"site:youtube.com " + queryKeyword, null, 10);

		int i = 0;

		Iterator<SearchResult> iter2 = googleList.iterator();
		while (iter2.hasNext()) {
			SearchResult resu = iter2.next();
			resu.setResultID("result" + i);
			resultList.add(resu);
			i++;
		}
		Iterator<SearchResult> iter3 = flickrList.iterator();
		while (iter3.hasNext()) {
			SearchResult resu = iter3.next();
			resu.setResultID("result" + i);
			resultList.add(resu);
			i++;
		}

		Iterator<SearchResult> iter = youtubeList.iterator();
		while (iter.hasNext()) {
			SearchResult resu = iter.next();
			if (resu.getType().equals("shockwave") && i < 30) {
				resu.setResultID("result" + i);
				resultList.add(resu);
				i++;
			}
		}
		return resultList;
	}

	/**
	 * Returns an Array 30 of {@link SearchResult} instances that suit the given
	 * keywords the first 10 results are from the google search, result 11-20
	 * are from flicker and the last 10 are from youtube.com
	 * 
	 * @param queryKeyword
	 *            The Keyword which is searched for
	 * @return
	 */
	public List<SearchResult> searchForGameParallel(String queryKeyword) {
		logger.info("Searching for " + queryKeyword
				+ " with the GameSearchEngine in parallel mode");
		List<SearchResult> resultList = new ArrayList<SearchResult>();
		GoogleSearchThread t1 = new GoogleSearchThread(queryKeyword, 10);
		FlickrSearchThread t2 = new FlickrSearchThread(queryKeyword);
		GoogleSearchThread t3 = new GoogleSearchThread(queryKeyword + " site:youtube.com", 10);
		ExecutorService executor = Executors.newCachedThreadPool();
		Future<List<SearchResult>> result1 = executor.submit(t1);
		Future<List<SearchResult>> result2 = executor.submit(t2);
		Future<List<SearchResult>> result3 = executor.submit(t3);

		while (!(result1.isDone() && result2.isDone() && result3.isDone())) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				logger
						.error(
								"Error while searching using the GameSearch GroupMe! search engine.",
								e);
				e.printStackTrace();
			}
		}

		if (result1.isDone() && result2.isDone() && result3.isDone()) {
			int i = 0;
			try {
				Iterator<SearchResult> iter1 = result1.get().iterator();
				while (iter1.hasNext()) {
					SearchResult resu = iter1.next();
					resu.setResultID("result" + i);
					resultList.add(resu);
					i++;
				}
				Iterator<SearchResult> iter2 = result2.get().iterator();
				while (iter2.hasNext()) {
					SearchResult resu = iter2.next();
					resu.setResultID("result" + i);
					resultList.add(resu);
					i++;
				}
				Iterator<SearchResult> iter3 = result3.get().iterator();
				while (iter3.hasNext()) {
					SearchResult resu = iter3.next();
					if (resu.getType().equals("shockwave") && i < 30) {
						resu.setResultID("result" + i);
						resultList.add(resu);
						i++;
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
				logger
						.error(
								"Error while searching using the GameSearch GroupMe! search engine.",
								e);
			} catch (ExecutionException e) {
				logger
						.error(
								"Error while searching using the GameSearch GroupMe! search engine.",
								e);
				e.printStackTrace();
			}
		}
		return resultList;
	}

	private class GoogleSearchThread implements Callable<List<SearchResult>> {
		public String keyword;
		public int results;
		public GoogleSearchThread(String keyword, int results) {
			this.keyword = keyword;
			this.results = results;
		}

		public List<SearchResult> call() throws Exception {
			{
				List<SearchResult> googleList = (new GoogleSearchEngine()
						.searchGoogle(keyword, null, results));
				return googleList;
			}
		}
	}

	private class FlickrSearchThread implements Callable<List<SearchResult>> {
		public String keyword;

		public FlickrSearchThread(String keyword) {
			this.keyword = keyword;

		}

		public List<SearchResult> call() throws Exception {
			{
				List<SearchResult> flickrList = (new FlickrSearchEngine()
						.searchForFlickrPhotos(keyword, 9));
				return flickrList;
			}
		}
	}

}
